package magicbattle.game;

import java.util.Iterator;
import java.util.Vector;

import magicbattle.game.character.*;
import magicbattle.game.character.effect.Buff;
import magicbattle.game.character.effect.EffectOverTime;

public class Player {

	private String name;

	private CharacterClass currentClass;

	private Attribute normalAttribute;
	private Attribute currentAttribute;

	private float health;
	private float mana;

	private Target target;

	private Vector<Buff> currentBuffs = new Vector<Buff>();
	private Vector<EffectOverTime> effectOverTime = new Vector<EffectOverTime>();

	public Player(String name, CharacterClass.CharacterClasses currentClass) {
		super();
		this.name = name;
		this.currentClass = new CharacterClass(currentClass);

		this.normalAttribute = this.currentClass.getStartAttribute();
		this.setCurrentAttribute();

		this.health = this.normalAttribute.getHealth();
		this.mana = this.normalAttribute.getMana();
	}

	// process time
	public void doTick() {
		// Buffs
		Iterator<Buff> iterBuff = this.currentBuffs.iterator();
		while (iterBuff.hasNext()) {
			((Buff) iterBuff.next()).doTick(this);
		}

		// Effect over Time
		Iterator<EffectOverTime> iterEffect = this.effectOverTime.iterator();
		while (iterEffect.hasNext()) {
			((EffectOverTime) iterEffect.next()).doTick(this);
		}

		// regenerate health and mana
		this.regeneratePoints();

	}

	// processing damage, with dodge, resistance
	public void processDamage(int damage, DamageType damageType) {

		switch (damageType) {
		case MAGICAL:
			// check magic resistance
			if ((Math.random() * 100) <= (this.currentAttribute
					.getMagicResistance() % 2)) {
				// player resists
				this.infoPlayerResistsToAllListener();
				return;
			} else {
				damage -= damage
						* (this.currentAttribute.getMagicResistance() / 100);
			}
			break;
		case PHYSICAL:
			// check dodge
			if ((Math.random() * 100) <= this.currentAttribute.getDodge()) {
				// player dodge
				this.infoPlayerDodgeToAllListener();
				return;
			} else {
				damage -= this.currentAttribute.getArmor();
			}
			break;
		case DOT:
			break;
		}

		// player get damage
		this.infoPlayerGetDamageToAllListener();

		// reduce health
		this.setHealth((damage * -1));
	}

	// processing heal
	public void processHeal(int amount) {

		// player get heal
		this.infoPlayerGetHealToAllListener();

		this.setHealth(amount);
	}

	// regenrate health and mana
	private void regeneratePoints() {

		// check if player is dead
		if (this.health <= 0) {
			this.health = 0;
			this.infoPlayerDiedToAllListener();
			return;
		}

		// health
		if (this.health >= this.currentAttribute.getHealth()) {
			this.health = this.currentAttribute.getHealth();
		} else {
			if (this.health + this.currentAttribute.getHealthRegeneration() >= this.currentAttribute
					.getHealth())
				;
		}
	}

	public void setHealth(float change) {
		// player died
		if ((this.health + change) <= 0) {
			this.health = 0;
			this.infoPlayerDiedToAllListener();
		} else {
			// calcuate health
			if ((this.health + change) <= this.currentAttribute.getHealth()) {
				this.health = this.currentAttribute.getHealth();
			} else {
				this.health += change;
			}
		}
	}

	// return false if no mana
	public boolean setMana(float change) {
		// player got no mana
		if ((this.mana + change) <= 0) {
			this.infoPlayerGotNoManaToAllListener();
			return false;
		} else {
			// calcuate health
			if ((this.mana + change) <= this.currentAttribute.getMana()) {
				this.mana = this.currentAttribute.getMana();
			} else {
				this.mana += change;
			}
			return true;
		}
	}

	public void addCurrentBuff(Buff buff) {
		this.currentBuffs.add(buff);
		this.setCurrentAttribute();
	}

	public void removeCurrentBuff(Buff buff) {
		this.currentBuffs.remove(buff);
		this.setCurrentAttribute();
	}

	public void addEffectOverTime(EffectOverTime effectOverTime) {
		this.effectOverTime.add(effectOverTime);
	}

	public void removeEffectOverTime(EffectOverTime effectOverTime) {
		this.effectOverTime.remove(effectOverTime);
	}

	public String getName() {
		return name;
	}

	public Attribute getCurrentAttribute() {
		return this.currentAttribute;
	}

	public void setCurrentAttribute() {

		this.currentAttribute = this.normalAttribute;

		Iterator<Buff> iter = this.currentBuffs.iterator();
		while (iter.hasNext()) {
			this.currentAttribute.addAttribute(((Buff) iter.next())
					.getAddedAttribute());
		}
	}

	public Attribute getNormalAttribute() {
		return this.normalAttribute;
	}

	public Target getTarget() {
		return target;
	}

	public void setTarget(Target target) {
		this.target = target;
	}

	public float getHealth() {
		return health;
	}

	public float getMana() {
		return mana;
	}

	/*
	 * ----------------------------------------------------------------*
	 * Listener *
	 * ----------------------------------------------------------------*
	 */
	private Vector<PlayerListener> playerListeners = new Vector<PlayerListener>();

	public void addPlayerListener(PlayerListener listener) {
		this.playerListeners.add(listener);
	}

	public void removePlayerListener(PlayerListener listener) {
		this.playerListeners.remove(listener);
	}

	private void infoPlayerDiedToAllListener() {
		Iterator<PlayerListener> iter = playerListeners.iterator();
		while (iter.hasNext()) {
			((PlayerListener) iter.next()).onPlayerDied(this);
		}
	}

	private void infoPlayerGetDamageToAllListener() {
		Iterator<PlayerListener> iter = playerListeners.iterator();
		while (iter.hasNext()) {
			((PlayerListener) iter.next()).onPlayerGetDamage(this);
		}
	}

	private void infoPlayerDodgeToAllListener() {
		Iterator<PlayerListener> iter = playerListeners.iterator();
		while (iter.hasNext()) {
			((PlayerListener) iter.next()).onPlayerDodge(this);
		}
	}

	private void infoPlayerResistsToAllListener() {
		Iterator<PlayerListener> iter = playerListeners.iterator();
		while (iter.hasNext()) {
			((PlayerListener) iter.next()).onPlayerResists(this);
		}
	}

	private void infoPlayerGetHealToAllListener() {
		Iterator<PlayerListener> iter = playerListeners.iterator();
		while (iter.hasNext()) {
			((PlayerListener) iter.next()).onPlayerGetHeal(this);
		}
	}

	private void infoPlayerGotNoManaToAllListener() {
		Iterator<PlayerListener> iter = playerListeners.iterator();
		while (iter.hasNext()) {
			((PlayerListener) iter.next()).onPlayerGotNoMana(this);
		}
	}

}
